﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace MyXnaGame
{
    public class PlayerSprite : AnimatedSprite
    {
        private const float MaxJumpTime = 0.65f;
        private const float JumpLaunchVelocity = -1500.0f;
        private const float GravityAcceleration = 3500.0f;
        private const float MaxFallSpeed = 600.0f;
        private const float JumpControlPower = 0.14f;

        private bool isJumping;
        private bool wasJumping = false;
        private float jumpTime;

        public PlayerSprite()
        {
        }

        public PlayerSprite(Vector2 position): base(position)
        {
        }

        //Load the texture for the sprite using the Content Pipeline
        public override void LoadContent(ContentManager content, string contentLocation)
        {
            base.LoadContent(content, contentLocation);
        }


        public void HandleInput(KeyboardState keyboardState, GamePadState gamePadState, InputState input, SafeArea safeArea)
        {
            //// Otherwise move the player position.
            Vector2 movement = Vector2.Zero;

            #region original movement tracking
            if (keyboardState.IsKeyDown(Keys.Left)
                || gamePadState.IsButtonDown(Buttons.LeftThumbstickLeft)
                || gamePadState.IsButtonDown(Buttons.DPadLeft))
            {
                speed.X = -5f;
                movement.X = -5f;
                direction = false;
            }
            else if (keyboardState.IsKeyDown(Keys.Right)
                || gamePadState.IsButtonDown(Buttons.LeftThumbstickRight)
                || gamePadState.IsButtonDown(Buttons.DPadRight))
            {
                speed.X = +5f;
                movement.X = +5f;
                direction = true;
            }
            else
            {
                speed.X = +0.0f;
            }

            #endregion

            if (keyboardState.IsKeyDown(Keys.Up)
                || keyboardState.IsKeyDown(Keys.Space)
                || gamePadState.IsButtonDown(Buttons.A))
                isJumping = true;
            else
                isJumping = false;


            Vector2 thumbstick = gamePadState.ThumbSticks.Left;

            if (movement.Length() > 1)
                movement.Normalize();

            spritePosition.X += movement.X * 6.0f;

            int safeLeft = safeArea.dx;
            int safeRight = safeArea.width - safeArea.dx - frameWidth;

            if (spritePosition.X < safeLeft)
            {
                spritePosition.X = safeLeft;
            }
            else if (spritePosition.X > safeRight)
            {
                spritePosition.X = safeRight;
            }

            spritePosition.Y += movement.Y;
        }

        //Update the Sprite and change it's position based on the passed in speed, direction and elapsed time.
        public override void Update(GameTime gameTime)
        {
            Animate(gameTime);

            base.Update(gameTime);
        }

        //Draw the sprite to the screen
        public override void Draw(SpriteBatch spriteBatch)
        {
            if (IsColliding)
                spriteColor = Color.Red;
            else
                spriteColor = Color.White;

            if (speed.X == 0.0f)
            {

                if (direction == true)
                {
                    if (isJumping)
                    {
                        spriteBatch.Draw(jumpAnimation.Texture, spritePosition, viewRect, spriteColor, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.FlipHorizontally, 0);
                    }
                    else
                    {
                        spriteBatch.Draw(idleAnimation.Texture, spritePosition, spriteColor);
                    }
                }
                else if (direction == false)
                {
                    if (isJumping)
                    {
                        spriteBatch.Draw(jumpAnimation.Texture, spritePosition, viewRect, spriteColor, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
                    }
                    else
                    {
                        spriteBatch.Draw(idleAnimation.Texture, spritePosition, null, spriteColor, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.FlipHorizontally, 0);
                    }
                }
            }


            else if (speed.X > 0.0f)
            {
                if (isJumping)
                {
                    spriteBatch.Draw(jumpAnimation.Texture, spritePosition, viewRect, spriteColor, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.FlipHorizontally, 0);
                }
                else
                {
                    spriteBatch.Draw(runAnimation.Texture, spritePosition, viewRect, spriteColor, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.FlipHorizontally, 0);
                }
            }

            else if (speed.X < 0.0f)
            {
                if (isJumping)
                {
                    spriteBatch.Draw(jumpAnimation.Texture, spritePosition, viewRect, spriteColor, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
                }
                else
                {
                    spriteBatch.Draw(runAnimation.Texture, spritePosition, viewRect, spriteColor, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
                }
            }

            base.Draw(spriteBatch);            
        }


        private void Animate(GameTime gametime)
        {
            time += (float)gametime.ElapsedGameTime.TotalSeconds;
            while (time > runAnimation.FrameTime)
            {
                time -= runAnimation.FrameTime;
                frameIndex = (frameIndex + 1) % runAnimation.FrameCount;
            }

            speed.Y = MathHelper.Clamp(speed.Y + GravityAcceleration * time, -MaxFallSpeed, MaxFallSpeed);
            speed.Y = DoJump(speed.Y, gametime);


            spritePosition.Y += (float)(speed.Y * time);
            spritePosition.Y = MathHelper.Clamp(spritePosition.Y, 0, 300);

            if (spritePosition.Y == 300 && speed.Y == 0)
            {
                wasJumping = false;
            }
            else
            {
                wasJumping = true;
            }

            if (isJumping)
            {

                viewRect = new Rectangle((frameIndex * jumpAnimation.FrameWidth), 0, jumpAnimation.FrameWidth, jumpAnimation.FrameHeight);
            }
            else
            {
                viewRect = new Rectangle((frameIndex * runAnimation.FrameWidth), 0, runAnimation.FrameWidth, runAnimation.FrameHeight);
            }
        }

        private float DoJump(float spd, GameTime gameTime)
        {

            if (spritePosition.Y == 300)
            {
                spd = 0;
            }

            if (isJumping)
            {
                if (!wasJumping || jumpTime > 0.0f)
                {
                    jumpTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
                }
                if (0.0f < jumpTime && jumpTime <= MaxJumpTime)
                {
                    spd = JumpLaunchVelocity * (1.0f - (float)Math.Pow(jumpTime / MaxJumpTime, JumpControlPower));
                }
                else
                {
                    jumpTime = 0.0f;
                }
            }
            else
            {
                jumpTime = 0.0f;
            }

            return spd;
        }

    }
}
